home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
oper_sys
/
presto
/
prest1_0.lha
/
src
/
scheduler_sig.C
< prev
next >
Wrap
C/C++ Source or Header
|
1991-12-11
|
9KB
|
348 lines
/*
* Signal handling nonsense. Signals need to be dealt with in their
* own class. Suggestions anyone?
*
* Main chore here is to catch all nasty signals in the parent so we can kill
* off all the children processes so they don't loop forever. (if the parent
* dies while "busy", he never gets unbusy) We can't protect against
* noncatchable signals in the parent, specificall SIGKILL. The best we can do
* is in the children, check every once in a while if the current ppid is not
* init. Really need a SIGPARENT (SIGPARNT?) to notify the children that its
* parent has changed.
*
* Last modified:
*
* bnb
* 1/27/88 to create
*
*/
#include <stddef.h>
#include <sys/types.h>
#include <signal.h>
#include <osfcn.h>
#include "presto.h"
//
// Route all normal default signals through the parent handler. Children
// should not be handling signals other than those WHICH are defined
// by presto. The whole idea of signals in this environment is strange.
// Signals are for processes. Signals should be for threads.
//
#ifdef mips
typedef void (*PFSigHandler)(int, int, sigcontext*);
#else
typedef int (*PFSigHandler)(int, int, sigcontext*);
#endif
sigvec_handler_t schedulerSigHandler(int sig, int code, struct sigcontext *scp);
sigvec_handler_t schedulerReapChild(int sig, int code, struct sigcontext *scp);
#ifdef sequent
static struct sigvec HAND_vec = {schedulerSigHandler, sigmask(SIGCHLD),1};
static struct sigvec CHLD_vec = {schedulerReapChild, 0, 1};
#endif /* sequent */
#ifdef sun
static struct sigvec HAND_vec = {schedulerSigHandler, sigmask(SIGCHLD),0};
static struct sigvec CHLD_vec = {schedulerReapChild, 0, 0};
#endif /* sun */
#ifdef vax
static struct sigvec HAND_vec = {schedulerSigHandler, sigmask(SIGCHLD),0};
static struct sigvec CHLD_vec = {schedulerReapChild, 0, 0};
#endif /* vax */
#ifdef mips
static struct sigvec HAND_vec = {schedulerSigHandler, sigmask(SIGCHLD),0};
static struct sigvec CHLD_vec = {schedulerReapChild, 0, 0};
#endif /* mips */
// default handler
static struct sigvec DFL_vec = {(PFSigHandler)SIG_DFL, 0, 0};
// force kernel sigvec to be called
#ifdef sequent
// #define SIGVEC_OS _sigvec
#define SIGVEC_OS sigvec
#endif /* sequent */
#ifdef sun
#define SIGVEC_OS sigvec
#endif /* sun */
#if defined(vax)||defined(mips)
#define SIGVEC_OS sigvec
#endif /* vax||mips */
//
// Force the parent to come through here on all signals that
// are "unpleasant" and not already handled.
//
void
Scheduler::initsighandlers(int setupdefaults)
{
struct sigvec sv;
int sig;
if (setupdefaults == 0) {
SIGVEC_OS(SIGCHLD, &CHLD_vec, (struct sigvec*)0);
return;
} else if (setupdefaults < 0) {
/*
* Don't be bothered by exiting children.
*/
SIGVEC_OS(SIGCHLD, &DFL_vec, (struct sigvec*)0);
return;
}
for (sig = 1; sig < NSIG; sig++) {
switch (sig) {
case SIGSTOP:
case SIGTSTP:
case SIGTTIN:
case SIGTTOU:
case SIGURG:
case SIGCONT:
case SIGIO:
case SIGCHLD:
case SIGWINCH:
continue;
default:
if (SIGVEC_OS(sig, (struct sigvec *) 0, &sv) < 0)
continue; // might make some noise
if (sv.sv_handler != (PFSigHandler)SIG_DFL)
continue;
(void) SIGVEC_OS(sig, &HAND_vec, (struct sigvec *)0);
}
}
}
//
// Parent proc comes here when it is time to kill everyone off.
// We do not necessarily get a core dump and we do not terminate
// ourselves. The caller must do that. We just kill off everybody else.
//
// if sig is negative, then we are not the parent, but a child proc
// who says KILL EVERYONE and forgewt about being polite. Child procs
// should use this when they detect that their parent is dead, but
// realize that everyone else must die also. If the root proc does this,
// nobody will be cleaned up after, but it would still work.
//
// Killer siblings can end up killing one another more than they need
// too, since we don't bother to mark thisproc as reaped before it
// nukes itself. It doesn't matter, in the worst case, some guys get killed
// more than once.
//
void
Scheduler::abort(int sig)
{
int pnum; // proc num of dying proc
int tpid; // pid of dying proc
union wait status; // and how they died
int waitforchild = 1; // presume we are parent
if (sig < 0) {
sig = -sig;
waitforchild = 0;
} else {
if (thisproc != sc_p_procs[0]) { // non root proc
kill(thisproc->pid(), sig); // just dies, parent
} // should clean up
//
// only root process gets this far
//
// no interruptions please
SIGVEC_OS(SIGCHLD, &DFL_vec, (struct sigvec*)0);
}
for (pnum = 0; pnum < sc_p_numschedulers; pnum++) {
Process *p = sc_p_procs[pnum];
if (p == thisproc) // we've got a JOB to do!
continue;
if (waitforchild && p->state()&S_REAPED)// not sibling killer
continue; // and already reaped
//
// Could either pass sig along to all children, in which
// case we might end up with tons of core files, or
// just say "to hell with it", one core file is enough.
// All we care about here is that everybody else stops
//
while (kill( p->pid(), SIGKILL) == 0)
continue; // force him to die
if (waitforchild == 0) // can't reap sibling
continue;
//
// pick up dead procs. Deal with the chance that
// multiple guys may die while we are doing this
//
do {
/* tpid = wait((int*)(&status));
*/
tpid = wait(&status);
if (tpid >= 0) {
int procnum = pidtoprocnum(tpid);
if (procnum >= 0)
sc_p_procs[procnum]->setstate(S_REAPED);
if (status.w_coredump)
storecore(pidtoprocnum(tpid));
}
} while (tpid != p->pid() && tpid >= 0);
}
//
// You may see this message more than once. Can't lock though
// cuz we could get killed in the lock, and then nobody else
// could proceed.
//
if (waitforchild == 0)
cerr << "Sibling ";
cerr << "Scheduler aborting with signal " << sig << "\n";
(void)SIGVEC_OS(sig, &DFL_vec, (struct sigvec*)0);
(void)kill(thisproc->pid(), sig);
// NOT REACHED (definitely)
}
//
// Write a core file. Hope we get to move it before someone else
// dumps. The first core file that dumps is called simply "core.First",
// all the rest are appended with the number of the processor
// that dumped.
// If you end up with a core.-1 file, then something bizarre happened to the
// pid to procnum mapping function and you may be missing some core files.
// As they say in te compouter business "This should never happen."
//
void
Scheduler::storecore(int pnum)
{
static int firstdump;
char cname[16];
if (firstdump == 0) {
sprintf(cname,"core.First");
firstdump = 1;
} else {
sprintf(cname,"core.%d", pnum);
}
cerr << "Caught core file " << (char*)&cname[0] << "\n";
(void)rename("core", cname);
}
int
Scheduler::pidtoprocnum(int pid)
{
int p;
for (p = 0; p < sc_p_numschedulers; p++)
if (pid == sc_p_procs[p]->pid())
return p; // presto pid
return -1;
}
//
// SIGCHLD handler. If we are the root proc, clean up the child, abort
// everyone else with the a clean signal. We never return from
// schedulerSigHandler
// unless we are already handloing some kind of a terminating signal.
//
sigvec_handler_t
schedulerReapChild(int sig, int code, struct sigcontext *scp)
{
union wait status;
int tpid;
int procnum;
if (sched == 0)
#ifdef mips
return;
#else
return 0; //???
#endif
if (thisproc != sched->sc_p_procs[0])
#ifdef mips
return;
#else
return 0; // who else and why would would it be caught?
#endif
tpid = wait3(&status, WNOHANG|WUNTRACED, 0);
if (tpid <= 0)
#ifdef mips
return;
#else
return 0 ; // spurious?
#endif
if (WIFSTOPPED(status)) // child could pause
#ifdef mips
return;
#else
return 0;
#endif
cerr << "Process " << tpid ;
if (WIFSIGNALED(status)) {
procnum = sched->pidtoprocnum(tpid);
if (procnum >= 0)
sched->sc_p_procs[procnum]->setstate(S_REAPED);
if (status.w_coredump)
sched->storecore(procnum);
cerr << " killed " << (unsigned short) status.w_termsig << "\n";
} else // must have just exited
cerr << " exited " << (unsigned short) status.w_termsig << "\n";
//
// don't bother to core dump everyone else
//
schedulerSigHandler(SIGKILL, code, scp);
//
// NOT REACHED (well... maybe)
//
sig=sig;
#ifdef mips
return;
#else
return 0;
#endif
}
//
//
// parent comes here when we get a "default" signal
//
sigvec_handler_t
schedulerSigHandler(int sig, int code, struct sigcontext *scp)
{
static int aborting; // avoid looping on signals
if (sched) { // once the axe is in motion
if (aborting == 0) {
aborting++;
sched->abort(sig);
// NOT REACHED
} else
#ifdef mips
return;
#else
return 0;
#endif
} else {
// sig ourselves
(void)SIGVEC_OS(sig, &DFL_vec, (struct sigvec*)0);
(void)kill(getpid(), sig);
// NOT REACHED
}
code=code;scp=scp;
#ifdef mips
return;
#else
return 0;
#endif
}